import Axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type CustomParamsSerializer
} from "axios";
import feedback from "@/utils/feedback";
import type {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { timeFormatDate } from "@/utils/util";
import loginUtil from "@/utils/loginUtils";
import httpConfig from "./httpConfig";

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 10000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** token过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新token */
  private static isRefreshing = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {
    // beforeRequestCallback: (request: PureHttpRequestConfig) => {
    //   console.log("执行beforeRequestCallback回调....");
    // }
  };

  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise(resolve => {
      PureHttp.requests.push((token: string) => {
        config.headers["Authorization"] = formatToken(token);
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        NProgress.start();

        console.log(import.meta.env);
        let loginParam = loginUtil.getLoginParams();
        //增加通用参数
        if (config.headers["Content-Type"] == null) {
          config.headers["Content-Type"] = "application/json;charset=utf-8";
        }
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        console.log("config---?", config);
        console.log("PureHttp.isRefreshing", PureHttp.isRefreshing);
        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = [
          httpConfig.system + "/auth/token/refresh",
          import.meta.env + "/system/auth/token/phone"
        ];
        return whiteList.find(url => config.url.indexOf(url) != -1)
          ? config
          : new Promise(resolve => {
              const data = getToken();
              console.log("getToken()", data);
              if (data) {
                const now = new Date().getTime();
                console.log("now", now);

                console.log("当前时间:" + timeFormatDate(new Date()));
                console.log(
                  "过期时间:" + timeFormatDate(new Date(data.expires))
                );
                console.log("data.expires-now", data.expires);
                console.log("now--", now);

                const expired = data.expires
                  ? parseInt(data.expires) - now <= 0
                  : true;
                console.log("expired", expired);

                // if (expired) {
                //   console.log("过期...", expired);

                //   if (!PureHttp.isRefreshing) {
                //     PureHttp.isRefreshing = true;
                //     console.log("已经过期...");

                //     // token过期刷新
                //     //拿到登录请求的参数
                //     useUserStoreHook()
                //       .handRefreshToken(data.refreshToken ?? data.accessToken)
                //       .then(res => {
                //         const token = res.data.accessToken;
                //         config.headers["Authorization"] = formatToken(token);
                //         PureHttp.requests.forEach(cb => cb(token));
                //         PureHttp.requests = [];
                //       })
                //       .finally(() => {
                //         PureHttp.isRefreshing = false;
                //       });
                //   }
                //   resolve(PureHttp.retryOriginalRequest(config));
                // } else {
                //   config.headers["Authorization"] = formatToken(
                //     data.accessToken
                //   );
                //   resolve(config);
                // }

                // 暂时使用此 不考虑刷新token
                config.headers["Authorization"] = formatToken(data.accessToken);
                resolve(config);
              } else {
                resolve(config);
              }
            });
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        console.log("response", response);

        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        console.log(
          "response.headers[Content-Type]",
          response.headers["Content-Type"]
        );
        console.log(
          "headers['content-disposition']",
          response.headers["content-disposition"]
        );

        if (
          response.headers["content-disposition"] &&
          response.headers["content-disposition"].indexOf(
            "attachment; filename"
          ) != -1
        ) {
          return response.data;
        }
        if (response.data.code !== 200) {
          //报错了 提示
          feedback.msgError(response.data.message);
          return Promise.reject(response.data);
        }

        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();
        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    //判断是否包含分页参数,有则加入到url请求上
    console.log("param", param);
    console.log("param", param?.data);

    if (param && param.data) {
      let pageIndex = param.data.pageNum
        ? param.data.pageNum
        : param.data.pageIndex;
      let pageSize = param.data.pageSize;
      url = url + "?pageIndex=" + pageIndex + "&pageSize=" + pageSize;
    }

    console.log("请求url:", url);
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("post", url, params, config);
  }

  /** 单独抽离的get工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("get", url, params, config);
  }
}

export const http = new PureHttp();
